﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: ProvisioningScriptViewModel 
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class ProvisioningScriptViewModel : TreeViewItemViewModel, IProduceValidationResults, ICanBeRemovedFromTree, IDataErrorInfo, ICleanupParamsAndPayload
    {       
        private readonly ProvisioningScript scriptCommand;
        private readonly TreeViewItemViewModel parentItemViewModel;
        private readonly VmRoleResourceExtensionViewModel vmRoleResourceExtensionViewModel;           
        private BoolParameterizableProperty alwaysReboot;
        private IntParameterizableProperty deploymentOrder;
        private EnumParameterizableProperty errorPolicy;
        private StringParameterizableProperty executable;
        private StringParameterizableProperty parameters;
        private StringParameterizableProperty exitCodeRegex;
        private IntParameterizableProperty maxOutputSize;
        private StringParameterizableProperty rebootExitCodeRegex;
        private BoolParameterizableProperty restartOnRetry;
        private BoolParameterizableProperty restartOnExitCodeReboot; 
        private StringParameterizableProperty scriptBlock;
        private EnumParameterizableProperty scriptType;
        private CredentialParameterizableProperty scriptCredential;
        private StringParameterizableProperty standardErrorPath;
        private StringParameterizableProperty standardErrorRegex;
        private StringParameterizableProperty standardInput;
        private StringParameterizableProperty standardOutputPath;
        private StringParameterizableProperty standardOutputRegex;
        private IntParameterizableProperty timeoutInSeconds;
        private StringParameterizableProperty workingDirectory;

        private ReferencedApplicationPayloadViewModel provisioningScriptPackage;

        public static class PropertyNames
        {
            public const string Summary = "Summary";          
            public const string AlwaysReboot = "AlwaysReboot";           
            public const string DeploymentOrder = "DeploymentOrder";
            public const string ErrorPolicy = "ErrorPolicy";
            public const string Executable = "Executable";
            public const string Parameters = "Parameters";
            public const string ExitCodeRegex = "ExitCodeRegex";
            public const string MaxOutputSize = "MaxOutputSize";
            public const string RebootExitCodeRegex = "RebootExitCodeRegex";
            public const string RestartOnRetry = "RestartOnRetry";
            public const string RestartOnExitCodeReboot = "RestartOnExitCodeReboot";
            public const string ScriptBlock = "ScriptBlock";
            public const string ScriptType = "ScriptType";
            public const string ScriptCredential = "ScriptCredential";
            public const string StandardErrorPath = "StandardErrorPath";
            public const string StandardErrorRegex = "StandardErrorRegex";
            public const string StandardInput = "StandardInput";
            public const string StandardOutputPath = "StandardOutputPath";
            public const string StandardOutputRegex = "StandardOutputRegex";
            public const string TimeoutInSeconds = "TimeoutInSeconds";
            public const string WorkingDirectory = "WorkingDirectory";
            public const string ProvisioningScriptPackage = "ProvisioningScriptPackage";
        }  

        public ProvisioningScriptViewModel(
            ProvisioningScript scriptCommand,
            TreeViewItemViewModel parentItemViewModel,
            VmRoleResourceExtensionViewModel resourceExtensionViewModel)
            : base(parentItemViewModel, true)
        {
            if (scriptCommand == null)
            {
                scriptCommand = new ProvisioningScript();
            }
            this.scriptCommand = scriptCommand;
            this.parentItemViewModel = parentItemViewModel;
            this.vmRoleResourceExtensionViewModel = resourceExtensionViewModel;
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
        }

        public string Summary
        {
            get
            {               
                if (((parentItemViewModel as WebDeployApplicationViewModel) != null) || ((parentItemViewModel as ScriptApplicationViewModel) != null))
                {
                    return "Script Command";
                }
                return "Provisioning Script";
            }
        }       

        public ProvisioningScript ProvisioningScript
        {
            get { return this.scriptCommand; }
        }

        public ReferencedApplicationPayloadViewModel ProvisioningScriptPackage
        {
            get
            {
                if (this.provisioningScriptPackage == null)
                {
                    Func<string> getter = () => this.scriptCommand.ApplicationPayloadId;
                    Action<string> setter = delegate(string value) { this.scriptCommand.ApplicationPayloadId = value; };
                    this.provisioningScriptPackage = new ReferencedApplicationPayloadViewModel(this.vmRoleResourceExtensionViewModel, ValidationHelper.PayloadType.ScriptFolder, getter, setter, false, PropertyNames.ProvisioningScriptPackage);
                }
                return this.provisioningScriptPackage;
            }
        }
       

        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty AlwaysReboot
        {
            get
            {
                if (this.alwaysReboot == null)
                {
                    Func<string> paramValueGetter = () =>
                        {
                            if (string.IsNullOrEmpty(this.scriptCommand.AlwaysReboot))
                            {
                                this.scriptCommand.AlwaysReboot = "false";
                            }
                            return this.scriptCommand.AlwaysReboot;
                        };                   
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.AlwaysReboot = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.AlwaysReboot;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultInitialValue = "false",
                        DefaultEnglishLabelText = "Always reboot"
                    };

                    this.alwaysReboot = new BoolParameterizableProperty(
                        PropertyNames.AlwaysReboot,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "Script Command always reboot",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo
                        );
                }
                return this.alwaysReboot;
            }
        }       
        
        /// <summary>
        /// int?
        /// </summary>      
        public IntParameterizableProperty DeploymentOrder
        {
            get
            {
                if (this.deploymentOrder == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.DeploymentOrder;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.DeploymentOrder = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DeploymentOrder;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "1",
                        DefaultEnglishLabelText = "Deployment Order"
                    };

                    this.deploymentOrder = new IntParameterizableProperty(
                        PropertyNames.DeploymentOrder,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Script Command Deployment Order",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo); //int?
                }              
                return this.deploymentOrder;
            }                    
        }

        /// <summary>
        /// ProvisioningScriptExecutionPolicy 
        /// </summary>
        public EnumParameterizableProperty ErrorPolicy
        {
            get
            {
                if (this.errorPolicy == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.ErrorPolicy;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.ErrorPolicy = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ErrorPolicy;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        Options = new List<string>(Enum.GetNames(typeof(ProvisioningScriptExecutionPolicy))),
                        DefaultEnglishLabelText = "Error policy",
                        DefaultInitialValue = ProvisioningScriptExecutionPolicy.FailOnMatch.ToString()
                    };

                    this.errorPolicy = new EnumParameterizableProperty(
                        PropertyNames.ErrorPolicy,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command error policy",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel, 
                        typeof(ProvisioningScriptExecutionPolicy),
                        true,
                        viewDefParamInfo);
                }
                return this.errorPolicy;
            }
        }

        public StringParameterizableProperty Executable
        {
            get
            {
                if (this.executable == null)
                {
                    if (this.scriptCommand.ExecutableAndParams == null)
                    {
                        this.scriptCommand.ExecutableAndParams = new ExecutableAndParams();
                    }
                    Func<string> paramValueGetter = () => this.scriptCommand.ExecutableAndParams != null ? this.scriptCommand.ExecutableAndParams.Executable : null;
                    Action<string> paramValueSetter = delegate(string value)
                        {
                            if (this.scriptCommand.ExecutableAndParams == null)
                            {
                                this.scriptCommand.ExecutableAndParams = new ExecutableAndParams();
                            }
                            this.scriptCommand.ExecutableAndParams.Executable = value;
                        };
                    Func<string> autoParamNameGetter = () => PropertyNames.Executable;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Executable"
                    };

                    this.executable = new StringParameterizableProperty(
                        PropertyNames.Executable,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command Executable",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                   
                        false,
                        viewDefParamInfo);
                }
                return this.executable;
            }
        }
            
        public StringParameterizableProperty Parameters
        {
            get
            {
                if (this.parameters == null)
                {
                    if (this.scriptCommand.ExecutableAndParams == null)
                    {
                        this.scriptCommand.ExecutableAndParams = new ExecutableAndParams();
                    }
                    Func<string> paramValueGetter =
                        () => this.scriptCommand.ExecutableAndParams != null ? this.scriptCommand.ExecutableAndParams.Parameters : null;
                    Action<string> paramValueSetter = delegate(string value)
                        {
                            if (this.scriptCommand.ExecutableAndParams == null)
                            {
                                this.scriptCommand.ExecutableAndParams = new ExecutableAndParams();
                            }
                            this.scriptCommand.ExecutableAndParams.Parameters = value;
                        };
                    Func<string> autoParamNameGetter = () => PropertyNames.Parameters;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Executable Parameters"
                    };

                    this.parameters = new StringParameterizableProperty(
                        PropertyNames.Parameters,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command Executable Parameters",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.parameters;
            }
        }

        public StringParameterizableProperty ExitCodeRegex
        {
            get
            {
                if (this.exitCodeRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.ExitCodeRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.ExitCodeRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ExitCodeRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "ExitCode Regex",
                        DefaultInitialValue = "[[1-9][[0-9]*"
                    };

                    this.exitCodeRegex = new StringParameterizableProperty(
                        PropertyNames.ExitCodeRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command ExitCodeRegex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                      
                        false,
                        viewDefParamInfo
                        );
                }
                return this.exitCodeRegex;
            }
        }

        public IntParameterizableProperty MaxOutputSize
        {
            get
            {
                if (this.maxOutputSize == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.MaxOutputSize;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.MaxOutputSize = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.MaxOutputSize;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Max Output Size",
                        DefaultInitialValue = "1048576"
                    };

                    this.maxOutputSize = new IntParameterizableProperty(
                        PropertyNames.MaxOutputSize,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Script Command Max Output Size",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                     
                        false,
                        viewDefParamInfo);
                }
                return this.maxOutputSize;
            }
        }
         
        public StringParameterizableProperty RebootExitCodeRegex
        {
            get
            {
                if (this.rebootExitCodeRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.RebootExitCodeRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.RebootExitCodeRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RebootExitCodeRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Reboot ExitCode Regex",
                        DefaultInitialValue = "{1641}|{3010}|{3011}"
                    };

                    this.rebootExitCodeRegex = new StringParameterizableProperty(
                        PropertyNames.RebootExitCodeRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command RebootExitCodeRegex parameter",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                     
                        false,
                        viewDefParamInfo);
                }
                return this.rebootExitCodeRegex;
            }
        }
     
        public BoolParameterizableProperty RestartOnRetry
        {
            get
            {
                if (this.restartOnRetry == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.RestartOnRetry;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.RestartOnRetry = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RestartOnRetry;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "Restart On Retry",
                        DefaultInitialValue = "false"
                    };

                    this.restartOnRetry = new BoolParameterizableProperty(
                        PropertyNames.RestartOnRetry,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "Restart On Retry",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.restartOnRetry;
            }
        }

        public BoolParameterizableProperty RestartOnExitCodeReboot
        {
            get
            {
                if (this.restartOnExitCodeReboot == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.RestartOnExitCodeReboot;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.RestartOnExitCodeReboot = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RestartOnExitCodeReboot;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultInitialValue = "false",
                        DefaultEnglishLabelText = "Restart On Exit Code Reboot"
                    };

                    this.restartOnExitCodeReboot = new BoolParameterizableProperty(
                        PropertyNames.RestartOnExitCodeReboot,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "Script Application Restart On Exit Code Reboot",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.restartOnExitCodeReboot;
            }
        }
      
        public StringParameterizableProperty ScriptBlock
        {
            get
            {
                if (this.scriptBlock == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.ScriptBlock;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.ScriptBlock = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptBlock;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.MultiLineString,
                        DefaultEnglishLabelText = "Script Command Script Block"
                    };

                    this.scriptBlock = new StringParameterizableProperty(
                        PropertyNames.ScriptBlock,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command Script Block",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                     
                        false,
                        viewDefParamInfo);
                }
                return this.scriptBlock;
            }
        }

        /// <summary>
        /// ProvisioningScriptType 
        /// </summary>            
        public EnumParameterizableProperty ScriptType
        {
            get
            {
                if (this.scriptType == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.ScriptType;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.ScriptType = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptType;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        DefaultEnglishLabelText = "Script Command Script Type",
                        Options = new List<string>(Enum.GetNames(typeof(ProvisioningScriptType)))
                    };

                    this.scriptType = new EnumParameterizableProperty(
                        PropertyNames.ScriptType,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command Script Type",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel, 
                        typeof(ProvisioningScriptType),
                        true,
                        viewDefParamInfo);
                }
                return this.scriptType;
            }
        }
     
        public CredentialParameterizableProperty ScriptCredential 
        { 
            get
            {
                if (this.scriptCredential == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.ScriptCredential;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.ScriptCredential = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptCredential;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Credential,
                        DefaultEnglishLabelText = "Script Command Credential"
                    };

                    this.scriptCredential = new CredentialParameterizableProperty(
                        PropertyNames.ScriptCredential,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Credential,
                        "Script Command Script Credential",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                      
                        false,
                        viewDefParamInfo);
                }
                return this.scriptCredential;
            }
        }
       
        public StringParameterizableProperty StandardErrorPath
        {
            get
            {
                if (this.standardErrorPath == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.StandardErrorPath;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.StandardErrorPath = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardErrorPath;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard error path",
                        DefaultInitialValue = "c:\\err.txt"
                    };

                    this.standardErrorPath = new StringParameterizableProperty(
                        PropertyNames.StandardErrorPath,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command standard error path",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                  
                        false,
                        viewDefParamInfo
                        );
                }
                return this.standardErrorPath;
            }
        }
       
        public StringParameterizableProperty StandardErrorRegex
        {
            get
            {
                if (this.standardErrorRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.StandardErrorRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.StandardErrorRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardErrorRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard error regex",
                        DefaultInitialValue = ".+"
                    };

                    this.standardErrorRegex = new StringParameterizableProperty(
                        PropertyNames.StandardErrorRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command standard error regex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                    
                        false,
                        viewDefParamInfo);
                }
                return this.standardErrorRegex;
            }
        }
    
        public StringParameterizableProperty StandardInput
        {
            get
            {
                if (this.standardInput == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.StandardInput;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.StandardInput = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardInput;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard input"
                    };

                    this.standardInput = new StringParameterizableProperty(
                        PropertyNames.StandardInput,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command standard input",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                  
                        false,
                        viewDefParamInfo);
                }
                return this.standardInput;
            }
        }
        
        public StringParameterizableProperty StandardOutputPath
        {
            get
            {
                if (this.standardOutputPath == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.StandardOutputPath;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.StandardOutputPath = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardOutputPath;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard output path",
                        DefaultInitialValue = "c:\\out.txt"
                    };

                    this.standardOutputPath = new StringParameterizableProperty(
                        PropertyNames.StandardOutputPath,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command standard output path",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                  
                        false,
                        viewDefParamInfo);
                }
                return this.standardOutputPath;
            }
        }
     
        public StringParameterizableProperty StandardOutputRegex
        {
            get
            {
                if (this.standardOutputRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.StandardOutputRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.StandardOutputRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardOutputRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard output regex"                        
                    };

                    this.standardOutputRegex = new StringParameterizableProperty(
                        PropertyNames.StandardOutputRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command StandardOutputRegex parameter",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                   
                        false,
                        viewDefParamInfo
                        );
                }
                return this.standardOutputRegex;
            }
        }

        public IntParameterizableProperty TimeoutInSeconds
        {
            get
            {
                if (this.timeoutInSeconds == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.TimeoutInSeconds;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.TimeoutInSeconds = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.TimeoutInSeconds;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Timeout in seconds",
                        DefaultInitialValue = 5000.ToString(CultureInfo.InvariantCulture)
                    };

                    this.timeoutInSeconds = new IntParameterizableProperty(
                        PropertyNames.TimeoutInSeconds,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Script Command timeout in seconds",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                    
                        true,
                        viewDefParamInfo);
                }
                return this.timeoutInSeconds;
            }
        }

        public StringParameterizableProperty WorkingDirectory
        {
            get
            {
                if (this.workingDirectory == null)
                {
                    Func<string> paramValueGetter = () => this.scriptCommand.WorkingDirectory;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptCommand.WorkingDirectory = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.WorkingDirectory;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Working directory"
                    };

                    this.workingDirectory = new StringParameterizableProperty(
                        PropertyNames.StandardOutputRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script Command working directory",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,                  
                        false,
                        viewDefParamInfo);
                }
                return this.workingDirectory;
            }
        }      

        protected override void LoadChildren()
        {
            // No children                          
        }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error           
        }

        public void Cleanup()
        {
            this.IsExpanded = true;
            ParametersAndPayloadCleanupHelper.CleanupParametersAndPayload(this, typeof(PropertyNames));
        }

        public string this[string propertyName]
        {
            get
            {
                string error = null;
                switch (propertyName)
                {
                    case PropertyNames.ScriptBlock:                
                        if (this.scriptBlock != null &&this.scriptBlock.PropertyValue != null &&
                            ((this.executable != null && this.executable.PropertyValue != null) || (this.parameters != null && this.parameters.PropertyValue != null)))
                        {
                            error = "Cannot specify both ScriptBlock and Executable/Parameters";
                        }
                        else if (this.scriptBlock != null &&this.scriptBlock.PropertyValue == null && (this.executable != null && this.executable.PropertyValue == null) )                                                        
                        {
                            error = "Must specify either ScriptBlock or Executable/Parameters";
                        }
                        break;                    
                    case PropertyNames.DeploymentOrder:
                        if (this.deploymentOrder != null && this.deploymentOrder.PropertyValue != null)
                        {
                            int depOrder;
                            if (int.TryParse(this.deploymentOrder.PropertyValue, out depOrder))
                            {
                                if (depOrder != 1)
                                {
                                    ProvisioningScriptType provisioningScriptType;
                                    if (this.scriptType != null && Enum.TryParse(this.scriptType.PropertyValue, out provisioningScriptType))
                                    {
                                        if (provisioningScriptType != ProvisioningScriptType.PreInstall &&
                                            provisioningScriptType != ProvisioningScriptType.OnProvisionFirst &&
                                            provisioningScriptType != ProvisioningScriptType.OnProvisionRest && 
                                            provisioningScriptType != ProvisioningScriptType.PostInstall)
                                        {
                                            error = "Deployment order (greather than 1) is valid only for PreInstall or PostInstall or OnProvisionFirst or OnProvisionRest";
                                        }
                                    }
                                }                               
                            }
                            else
                            {
                                error = "Deployment order specified needs to be a valid positive integer";
                            }                            
                        }
                        if (error == null)
                        {
                            if (this.Parent as ApplicationProfileViewModel != null)
                            {
                                error = ValidationHelper.ValidateDeploymentOrderUniquenessForProvisioningScripts(this.vmRoleResourceExtensionViewModel.ResourceExtensionDefinition, this.ProvisioningScript);
                            }
                            else
                            {
                                WebDeployApplicationViewModel webDeployApplicationViewModel = this.Parent as WebDeployApplicationViewModel;
                                if ((webDeployApplicationViewModel != null) && (webDeployApplicationViewModel.WebDeployApplication != null))
                                {
                                    error = ValidationHelper.ValidateDeploymentOrderUniquenessForScriptCommandsInAnApplication(webDeployApplicationViewModel.WebDeployApplication.ScriptCommands, this.ProvisioningScript);
                                }
                                else
                                {
                                    ScriptApplicationViewModel scriptApplicationViewModel = this.Parent as ScriptApplicationViewModel;
                                    if ((scriptApplicationViewModel != null) && (scriptApplicationViewModel.ScriptApplication != null))
                                    {
                                        error = ValidationHelper.ValidateDeploymentOrderUniquenessForScriptCommandsInAnApplication(scriptApplicationViewModel.ScriptApplication.ScriptCommands, this.ProvisioningScript);
                                    }
                                    else
                                    {
                                        SqlDacApplicationViewModel sqlDacApplicationViewModel = this.Parent as SqlDacApplicationViewModel;
                                        if ((sqlDacApplicationViewModel != null) && (sqlDacApplicationViewModel.SqlDacApplication != null))
                                        {
                                            error = ValidationHelper.ValidateDeploymentOrderUniquenessForScriptCommandsInAnApplication(sqlDacApplicationViewModel.SqlDacApplication.ScriptCommands, this.ProvisioningScript);
                                        }
                                    }
                                }

                            }
                        }

                        break;
                }
                return error;              
            }
        }

        public string Error { get; set; }
    }
}


